/**
 * BaseCanvas类
 * @constructor
 * @param {Object} options BaseCanvas的参数
 * @param {string} options.selector canvas选择器,只会选中第一个符合条件的元素
 */
function BaseCanvas(options) {
  options = Object.assign({}, {

  }, options);
  //canvas对象
  this.canvas = document.querySelector(options.selector);
  //canvas上下文
  this.context = this.canvas.getContext('2d');
  // requestAnimationFrame id
  this.rafId = null;
  // 标记还需不需要调用requestAnimationFrame
  this.canRaf = true;
  // canvas中的元素实例
  this.allCanvasElements = {};
}

/**
 * clear方法,清空整个画布的方法
 */
BaseCanvas.prototype.clear = function () {
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}

/**
 * afterDraw方法,必须在子类中实现,否则抛出异常;
 * 在draw()中调用,可用于修改this.allCanvasElements的属性,以期改变绘制结果
 * @abstract
 */
BaseCanvas.prototype.afterDraw = function () {
  throw new Error('not implemented');
}

/**
 * draw方法,绘制整个画布的方法,遍历this.allCanvasElements调用draw()方法
 */
BaseCanvas.prototype.draw = function () {
  for (key in this.allCanvasElements) {
    if (this.allCanvasElements.hasOwnProperty(key)) {
      this.allCanvasElements[key].draw(this.context);
    }
  }
  this.afterDraw();
}

/**
 * step方法,重复不停的绘制整个画布.为了避免重复调用step(),请不要直接调用这个方法,但是可以直接调用run方法
 */
BaseCanvas.prototype.step = function () {
  this.clear();
  this.draw();
  //requestAnimationFrame支持IE10 +
  if(!this.canRaf) return;
  this.rafId = requestAnimationFrame(function () {
    this.step()
  }.bind(this));
}

/**
 * run方法,该方法的目的是避免重复调用step()
 */
BaseCanvas.prototype.run = function () {
  if (this.rafId) {
    console.warn('当前有正在执行的step');
    return;
  }
  this.canRaf = true;
  this.step();
}

/**
 * cancelRun方法,取消重复调用step()
 */
BaseCanvas.prototype.cancelRun = function () {
  // cancelAnimationFrame和canRaf要结合起来使用,不然在某些时候回有问题,不能停止回调
  cancelAnimationFrame(this.rafId);
  this.canRaf = false;
  this.rafId = null;
}

/**
 * destroy方法,主要是取消定时器和清空画布
 */
BaseCanvas.prototype.destroy = function () {
  this.cancelRun();
  this.clear();
}